<!-- components/Basic/Popover/Popover.svelte -->
<script lang="ts">
	import { onDestroy, onMount, untrack } from 'svelte';
	import Portal from 'svelte-portal';
	import PopoverSlot from './PopoverSlot.svelte'; // 引入上面的 PopoverSlot
	import { ensurePortalContainer } from '$lib/utils/container/ensurePortalContainer'; // 假设你有这个工具
	import { getElementRelativePos } from '$lib/utils/position/getElementPos'; // 假设你有这个工具
	import { type Placement } from './types';

	export type TriggerType = 'click' | 'hover' | 'manual';

	interface Props {
		// 触发方式
		trigger?: TriggerType;
		// 弹出方向
		placement?: Placement;
		// 手动控制显示 (trigger='manual' 时有效)
		visible?: boolean;
		// 是否禁用
		disabled?: boolean;
		// 偏移量
		offset?: number;
		// 内容类名
		contentClass?: string;
		// 样式
		style?: string;
		// 动画时间
		transitionDuration?: number;
		// 插槽
		triggerSnippet?: any; // 触发器插槽
		contentSnippet?: any; // 内容插槽
		// 事件回调
		onVisibleChange?: (visible: boolean) => void;
	}

	let {
		trigger = 'click',
		placement = 'auto',
		visible = $bindable(false),
		disabled = false,
		offset = 2,
		contentClass = '',
		style = '',
		transitionDuration = 150,
		triggerSnippet,
		contentSnippet,
		onVisibleChange
	}: Props = $props();

	// 内部状态
	let internalVisible = $state(false);
	// 最终可见性（受控或非受控）
	let isVisible = $derived(trigger === 'manual' ? visible : internalVisible);

	let triggerRef: HTMLElement | undefined = $state(undefined);
	let popoverRef: HTMLElement | undefined = $state(undefined);
	let portalTarget: HTMLElement | undefined = $state(undefined);

	// 触发元素位置信息
	let triggerRect = $state({
		top: 0,
		left: 0,
		bottom: 0,
		right: 0,
		width: 0,
		height: 0
	});

	// 更新位置信息的函数
	const updateTriggerRect = () => {
		if (triggerRef) {
			// 如果你有 getElementRelativePos 工具函数，用它；否则用 getBoundingClientRect
			// getElementRelativePos 通常处理滚动偏移
			triggerRect = getElementRelativePos
				? getElementRelativePos(triggerRef)
				: triggerRef.getBoundingClientRect();
		}
	};

	// 显示弹窗
	const show = () => {
		if (disabled) return;
		updateTriggerRect();
		if (trigger !== 'manual') {
			internalVisible = true;
			if (onVisibleChange) onVisibleChange(true);
		}
	};

	// 隐藏弹窗
	const hide = () => {
		if (trigger !== 'manual') {
			internalVisible = false;
			if (onVisibleChange) onVisibleChange(false);
		}
	};

	// 切换显示
	const toggle = () => {
		if (isVisible) hide();
		else show();
	};

	// --- 事件处理 ---

	// Click 触发
	const handleClick = (e: MouseEvent) => {
		if (trigger === 'click') {
			e.stopPropagation(); // 防止冒泡立即关闭
			toggle();
		}
	};

	// Hover 触发
	let hoverTimer: any;
	const handleMouseEnter = () => {
		if (trigger === 'hover') {
			clearTimeout(hoverTimer);
			show();
		}
	};

	const handleMouseLeave = () => {
		if (trigger === 'hover') {
			hoverTimer = setTimeout(() => {
				hide();
			}, 200); // 延迟关闭，给用户移动到弹窗上的时间
		}
	};

	// 点击外部关闭逻辑
	const handleClickOutside = (event: MouseEvent) => {
		if (!isVisible || trigger === 'manual') return;

		const target = event.target as Node;
		// 如果点击在触发器内，由 handleClick 处理（避免冲突）
		if (triggerRef && triggerRef.contains(target)) return;
		// 如果点击在弹窗内，不关闭
		if (popoverRef && popoverRef.contains(target)) return;

		hide();
	};

	onMount(() => {
		// 确保 Portal 容器存在
		portalTarget = ensurePortalContainer('popovers-container'); // 你的工具函数，或 document.body

		document.addEventListener('mousedown', handleClickOutside);

		// 监听滚动更新位置（可选，视需求而定）
		// window.addEventListener('scroll', updateTriggerRect, true);
	});

	onDestroy(() => {
		if (typeof document !== 'undefined') {
			document.removeEventListener('mousedown', handleClickOutside);
		}
	});

	// 同步 manual 模式下的 visible
	$effect(() => {
		if (trigger === 'manual' && visible) {
			// 当外部设为 true 时，更新位置
			updateTriggerRect();
		}
	});
</script>

<!-- 触发器包裹容器 -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
	class="popover-trigger"
	bind:this={triggerRef}
	onclick={handleClick}
	onmouseenter={handleMouseEnter}
	onmouseleave={handleMouseLeave}
	style:display="inline-block"
>
	{@render triggerSnippet?.()}
</div>

<!-- 弹窗内容 -->
{#if isVisible}
	<Portal target={portalTarget}>
		<PopoverSlot
			bind:popoverRef
			{placement}
			{triggerRect}
			{offset}
			{contentClass}
			{style}
			{transitionDuration}
		>
			{@render contentSnippet?.()}
		</PopoverSlot>
	</Portal>
{/if}
